1

这篇文章算是我职业生涯中的第一篇技术博文吧,有些地方可能表达得不是很好,还望大家多多包涵哈^_^!

正文

JavaScript的简单类型有数字、字符串、布尔值(true、false)、null值和underfind值,其他所有的值都是对象。

数字、字符串和布尔值“貌似”是对象,因为它们都拥有方法,但是它们是不可变的。而JavaScript中的对象是可控的键控集合

在JavaScript中,数组是对象,函数是对象,正则表达式是对象,当然,对象自然也是对象。

对象是属性的容器,其中每个属性都拥有名字和值(name-value)。属性名可以是包括字符串在内的任意字符串,属性值可以是除undefined值之外的任意值。

JavaScript中的对象是无类别(class-free)的,它对新属性的名字和值没有约束。对象适合用于收集和管理数据。对象可以包含其他对象,所以它们可以容易的表示成树形或图形结构。

JavaScript包括一个原型链特性(这是JS对象中很重要的一个特性,具体用法以后我会发一篇针对原型链及其用法的文章进行专门说明),允许对象继承另一个对象的属性,正确地使用它能减少对象初始化的时间和内存耗损。

1. 对象字面量

对象字面量,提供了一种非常方便的创建新对象值得表示法,即包围在一对花括号中的零个或多个“名/值”对(也称为键值对),它可以出现在任何允许表达式出现的地方。

javascriptvar empty_object = {};
var batman = {
    'first-name': 'Bruce',
    'last-name': 'Wayne'
};

属性名可以是包括空字符串在内的任何字符串,不过,一个合法的变量标识符,不能是保留字,虽然不强调用引号括住,但是,像“first-name”、“first name”这类含有“-”或是空格的属性名,是必须加上引号括住的。逗号用来分隔多个“名/值”对。

属性值可以从包括另一个对象字面量在内的任意表达式中获得,而对象是可嵌套的。

javascriptvar flight = {
    airline: 'Domestic',
    number: 1024,
    departure: {
        IATA: 'SZ',
        time: '2015-08-03 15:00:00',
        city: 'shenzhen'
    },
    arrival: {
        IATA: 'BJ',
        time: '2015-08-04 00:00:00',
        city: 'beijing'
    }
};

2. 检索

要检索对象中包含的值(或属性值或方法或其它),可以采用在 [] 后缀中括住一个字符串表达式的方式,如果字符串表达式是一个合法js标识符且不为保留字的常数,那么优先考虑用 . 表示法,因为它更紧凑且可读性更好。

javascriptbatman['first-name']    // "Bruce"
flight.departure.city   // "shenzhen"

如果你尝试检索一个并不存在的成员元素的值(这里的属性表达式是严格区分大小写的),将返回一个undefined值。

javascriptbatman['middle-name']   // undefined
flight.status           // undefined
batman['FIRST-NAME']    // undefined

|| 运算符可以用来填充默认值:

javascriptvar middle = batman['middle-name'] || '(none)';
var status = flight.status || 'unknown';

尝试检索一个undefined值将会导致TypeError异常,这可以通过 && 运算符来避免错误。

javascriptflight.equipment                             // undefined
flight.equipment.model                       // throw "TypeError"
flight.equipment && flight.equipment.model   // undefined

3. 更新

对象中的值可以通过赋值语句来更新。

如果属性名已经存在于对象中,那么这个属性值将被替换。

javascriptbatman['first-name'] = 'Damian';

如果对象之前并没有这个属性名,那么该属性将会被扩充到该对象中。

javascriptbatman['middle-name'] = 'AI';
batman['nickname'] = 'Robin';
flight.equipment = {
    model: 'Boeing 777'
};
flight.status = 'overdue';

4. 引用

对象通过引用来传递,它们永远不会被拷贝。

javascriptvar x = batman;
x.nickname = 'Joker';
var nick = batman.nickname;  // 因为x和batman是指向同一个对象的引用,所以nick为"Joker"
var a = {},b = {},c = {};    // a、b、c 每个都分别引用一个不同的空对象
a = b = c = {};              // a、b、c 都引用一个相同的空对象

5. 原型

每个对象都会连接到一个原型对象,并且它可以从中继承属性。所有通过字面量创建的对象,都连接到 Object.prototype 这个JS中的标准的对象。

当创建一个新对象时,可以选择某个对象作为它的原型,给Object增加一个beget方法,这个beget方法创建一个使用原对象作为其原型的新对象,这个我们以后会在专门的博文做详细了解。

javascriptif(typeof Object.beget !== 'function'){
    Object.beget = function(o){
        var F = function(){};
        F.prototype = o;
        return new F();
    };
};

var next_batman = Object.beget(batman);

原型连接在更新时是不起作用的,当我们对某个对象做出改变时,不会触及到该对象的原型:

javascriptnext_batman['first-name'] = 'Damian55';
next_batman['middle-name'] = 'Ai22';
next_batman.nickname = 'Robin5';

原型连接只有在检索值的时候才会被用到。如果我们尝试去获取对象的某个属性值,且该对象没有该属性名,那么,JS会试着从原型对象中获取属性值,如果那个原型对象也没有该属性,则再从它的原型中寻找,以此类推,直到最后到达终点Object.prototype,若想要的属性完全不存在于原型链中,则返回undefined值,这个过程称为委托

原型关系是一种动态的关系,如果我们在原型中添加一个新的属性,该属性会立即对所有基于该原型创建的对象可见。

javascriptbatman.profession = 'JSL';
next_batman.profession;      // 'JSL'

6. 反射

检查对象并确认对象有什么属性,可以去检索该属性并验证取得的值。而确定属性的类型,可以使用typeof操作符。

javascripttypeof flight.number        // 'number'
typeof flight.status        // 'string'
typeof flight.arrival       // 'object'
typeof flight.manifast      // 'undefined'

请务必注意原型链中的任何属性也会产生一个值:

javascripttypeof flight.toString      // 'function'
typeof flight.constructor   // 'function'

有两种方法去处理这些不需要的属性:

  • 让你的程序检查并剔除函数值,一般来说,做反射的目标是数据,因此其中一些值可能会是函数。
  • 使用hasOwnProperty方法,如果对象拥有独立属性,它将返回true。

另外,hasOwnProperty方法不会检查原型链。

javascriptflight.hasOwnProperty('number');        // true
flight.hasOwnProperty('constructor');   // false

7. 枚举

for in 语句可用来遍历一个对象中的所有属性名,当然,也包括函数和我们可能不关心的原型中的属性,所以我们有必要过滤掉不必要的值。
最常用的过滤器(即过滤原型中的属性)是hasOwnProperty方法,以及使用typeof来排除函数:

javascriptvar name;
for(name in next_batman){
    if(typeof next_batman[name] !== 'function'){
        document.writeln(name + ': ' + next_batman[name]);
    }
}

以上,属性名出现的顺序是不确定的,因此要想确保属性以特定的顺序出现,最好是完全避免使用 for in 语句,而是创建一个数组,在其中以正确的顺序包含属性名:

javascriptvar i;
var properties = ['first-name','middle-name','last-name','profession'];
for(i = 0;i < properties.length;i ++){
    document.writeln(properties[i] + ': ' + next_batman[properties[i]]);
}

通过使用普通for而不是for in ,可以得到我们想要的属性,而不用担心可能发掘出原型链中的属性,并按正确的顺序取得它们的值。

8. 删除

delete运算符可以用来删除对象的属性,它将会移除该对象的确定包含的属性,它不会触及原型链中的任何对象。

删除对象的属性可能会让来自原型链中的属性浮现出来。

javascriptnext_batman.nickname        // 'Robin5'
// 删除next_batman的nickname属性,从而暴露出原型的nickname的属性值
delete next_batman.nickname; 
next_batman.nickname;       // 'Robin'

9. 减少全局变量污染

JS可以随意定义可保存所有应用资源的全局变量,不幸的是,全局变量会削弱程序的灵活性,所以应该避免。

最小化使用全局变量的一个方法是在你的应用中只创建唯一一个全局变量:

javascriptvar MyApp = {};

该变量此时变成了你的应用容器:

javascriptMyApp.batman = {
    'first-name': 'Bruce',
    'last-name': 'Wayne'
};

MyApp.flight = {
    airline: 'Domestic',
    number: 1024,
    departure: {
        IATA: 'SZ',
        time: '2015-08-03 15:00:00',
        city: 'shenzhen'
    },
    arrival: {
        IATA: 'BJ',
        time: '2015-08-04 00:00:00',
        city: 'beijing'
    }
};

只要把多个全局变量都整理在同一个命名空间下,你将显著降低与其他应用程序、组件或类库之间产生糟糕的相互影响(即耦合度高)的可能性,也使其变得更容易阅读,因为MyApp.batman指向的时顶层结构。当然,也可以使用闭包来进行信息隐藏,它是另一种有效减少全局污染的方法。


羅聲門X
232 声望6 粉丝

爱编程、爱旅行的四次元逗比